import os
import json
from flask import Flask, request, jsonify, session
import fitz
from docx import Document
from openai import OpenAI
import pymongo
from pymongo import MongoClient
from sentence_transformers import SentenceTransformer
import requests
from bs4 import BeautifulSoup
from werkzeug.security import generate_password_hash, check_password_hash
import logging
from bson.objectid import ObjectId
import datetime
import requests

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

app = Flask(__name__)
app.secret_key = os.urandom(24)

# 假设使用 MongoDB 存储历史记录
client_his = pymongo.MongoClient('mongodb://localhost:27017/')
db_his = client_his['chat_history']
history_collection = db_his['conversations']


# MongoDB 用户数据库配置
client_user = pymongo.MongoClient('mongodb://localhost:27017/')
db_user = client_user['user_database']
user_collection = db_user['users']



# 提取文本函数
def extract_text(file_path):
    """
    根据文件类型提取文本内容
    参数:
        file_path (str): 待解析的文件路径
    返回:
        str: 提取的文本内容或错误信息
    """
    
    try:
        file_ext = os.path.splitext(file_path)[1].lower()
        
        if file_ext == '.pdf':
            # PDF处理（使用PyMuPDF库）
            text = ""
            with fitz.open(file_path) as doc:
                for page in doc:
                    text += page.get_text()
            return text
            
        elif file_ext == '.docx':
            # Word处理
            doc = Document(file_path)
            return '\n'.join([para.text for para in doc.paragraphs])
            
        elif file_ext == '.txt':
            # 文本文件
            with open(file_path, 'r', encoding='utf-8') as f:
                return f.read()
                
        else:
            return "不支持的文件格式"
    except Exception as e:
        return f"文件解析失败: {str(e)}"


client_ai = OpenAI(
    api_key = "c27a61cf-658c-4b54-a4e9-d1a4574e6738",
    base_url = "https://ark.cn-beijing.volces.com/api/v3",
)

# 查询 AI 函数
def query_ai(prompt, context=[]):
    """
    向DeepSeek AI接口发送查询请求
    参数:
        prompt (str): 用户输入的提问内容
        context (list): 上下文信息列表，默认为空列表
    返回:
        dict: 包含AI响应结果的JSON对象
    """
    # 确保 context 中的 role 值符合要求
    valid_context = []
    for msg in context:
        if msg['role'] == 'ai':
            valid_context.append({'role': 'assistant', 'content': msg['content']})
        else:
            valid_context.append(msg)

    # 合并上下文和当前提问
    messages = valid_context + [{"role": "user", "content": prompt}]
    try:
        response = client_ai.chat.completions.create(
            model='deepseek-r1-250528',
            messages=messages,
            temperature=0
        )
        return {
            "text": response.choices[0].message.content,
            "confidence": 1.0  # 实际应根据API响应添加置信度判断
        }
    except Exception as e:
        # 确保异常时返回字典类型
        return {
            "text": f"错误：{str(e)}",
            "confidence": 0.0
        }


# 注册接口
@app.route('/api/register', methods=['POST'])
def register():
    data = request.get_json()
    if not data:
        logging.error('请求数据为空或格式错误')
        return jsonify({'message': '请求数据为空或格式错误'}), 400

    username = data.get('username')
    password = data.get('password')

    if not username or not password:
        logging.info('注册失败：用户名和密码不能为空')
        return jsonify({'message': '用户名和密码不能为空'}), 400

    try:
        logging.info('检查用户名是否已存在')
        if user_collection.find_one({'username': username}):
            logging.info(f'注册失败：用户名 {username} 已存在')
            return jsonify({'message': '用户名已存在'}), 400

        # 加密密码
        hashed_password = generate_password_hash(password)

        # 插入新用户
        logging.info(f'插入新用户 {username}')
        user_collection.insert_one({'username': username, 'password': hashed_password})
        logging.info(f'用户 {username} 注册成功')
        return jsonify({'message': '注册成功'}), 201

    except Exception as e:
        logging.error(f'注册过程中出现未知错误: {str(e)}')
        return jsonify({'message': f'注册失败: {str(e)}'}), 500

# # 登录接口
# @app.route('/api/login', methods=['POST'])
# def login():
#     data = request.get_json()
#     username = data.get('username')
#     password = data.get('password')

#     if not username or not password:
#         logging.info('登录失败：用户名和密码不能为空')
#         return jsonify({'message': '用户名和密码不能为空'}), 400

#     try:
#         # 查询用户信息
#         user = user_collection.find_one({'username': username})

#         if user and check_password_hash(user['password'], password):
#             session['user_id'] = str(user['_id'])
#             logging.info('登录成功')
#             return jsonify({'message': '登录成功'}), 200
#         else:
#             logging.info('登录失败：用户名或密码错误')
#             return jsonify({'message': '用户名或密码错误'}), 401

#     except Exception as e:
#         logging.error(f'登录失败: {str(e)}')
#         return jsonify({'message': f'登录失败: {str(e)}'}), 500


# 登录接口
@app.route('/api/login', methods=['POST'])
def login():
    data = request.get_json()
    username = data.get('username')
    password = data.get('password')
    if not username or not password:
        logging.info('登录失败：用户名和密码不能为空')
        return jsonify({'message': '用户名和密码不能为空'}), 400

    try:
        logging.info(f'尝试查找用户: {username}')
        user = user_collection.find_one({'username': username})
        if user:
            logging.info('找到用户，开始验证密码')
        else:
            logging.info('未找到用户')

        if user and check_password_hash(user['password'], password):
            session['user_id'] = str(user['_id'])
            session['username'] = username
            logging.info('登录成功')
            return jsonify({'message': '登录成功', 'username': username}), 200
        else:
            logging.info('登录失败：用户名或密码错误')
            return jsonify({'message': '用户名或密码错误'}), 401

    except Exception as e:
        logging.error(f'登录失败: {str(e)}')
        return jsonify({'message': f'登录失败: {str(e)}'}), 500
    
# 检查登录状态接口
@app.route('/api/check_login', methods=['GET'])
def check_login():
    if 'user_id' in session:
        return jsonify({'isLoggedIn': True, 'username': session.get('username')}), 200
    else:
        return jsonify({'isLoggedIn': False}), 200

# 注销接口
@app.route('/api/logout', methods=['POST'])
def logout():
    try:
        if 'user_id' in session:
            # 清除会话信息
            session.pop('user_id', None)
            logging.info('用户注销成功')
            return jsonify({'message': '注销成功'}), 200
        else:
            logging.info('用户未登录，无需注销')
            return jsonify({'message': '用户未登录'}), 401
    except Exception as e:
        logging.error(f'注销失败: {str(e)}')
        return jsonify({'message': f'注销失败: {str(e)}'}), 500



# 获取用户聊天历史记录接口
@app.route('/api/history', methods=['GET'])
def get_history():
    if 'user_id' not in session:
        logging.info('用户未登录，无法获取历史记录')
        return jsonify({'message': '用户未登录'}), 401
    user_id = session['user_id']
    try:
        # 转换 user_id 为 ObjectId 类型
        user_id_obj = ObjectId(user_id)
        logging.info(f'开始为用户 {user_id} 查询历史记录')
        history = list(history_collection.find({'user_id': user_id_obj}, {'_id': 1, 'messages': 1}))
        logging.info(f'查询到 {len(history)} 条历史记录')
        conversations = []
        for record in history:
            record['id'] = str(record.pop('_id'))
            conversations.append(record)
        return jsonify({'conversations': conversations}), 200
    except Exception as e:
        logging.error(f'获取历史记录失败: {str(e)}')
        return jsonify({'message': f'获取历史记录失败: {str(e)}'}), 500
    

# 保存或更新历史记录接口
@app.route('/api/history', methods=['PUT'])
def update_history():
    if 'user_id' not in session:
        return jsonify({'message': '用户未登录'}), 401
    user_id = session['user_id']
    data = request.get_json()
    conversation_id = data.get('id')
    messages = data.get('messages')
    try:
        user_id_obj = ObjectId(user_id)
        if conversation_id:
            # 更新已有对话记录
            history_collection.update_one(
                {'_id': ObjectId(conversation_id), 'user_id': user_id_obj},
                {'$set': {'messages': messages}}
            )
        else:
            # 插入新对话记录
            new_record = {'user_id': user_id_obj, 'messages': messages}
            result = history_collection.insert_one(new_record)
            conversation_id = str(result.inserted_id)
        return jsonify({'id': conversation_id}), 200
    except Exception as e:
        logging.error(f'更新历史记录失败: {str(e)}')
        return jsonify({'message': f'更新历史记录失败: {str(e)}'}), 500


# 删除历史记录接口
@app.route('/api/history/<conversation_id>', methods=['DELETE'])
def delete_history(conversation_id):
    if 'user_id' not in session:
        return jsonify({'message': '用户未登录'}), 401
    user_id = session['user_id']
    try:
        user_id_obj = ObjectId(user_id)
        conversation_id_obj = ObjectId(conversation_id)  # 将 conversation_id 转换为 ObjectId
        logging.info(f'尝试删除对话，用户 ID: {user_id}，对话 ID: {conversation_id}')
        result = history_collection.delete_one(
            {'_id': conversation_id_obj, 'user_id': user_id_obj}
        )
        if result.deleted_count > 0:
            logging.info(f'对话删除成功，用户 ID: {user_id}，对话 ID: {conversation_id}')
            return jsonify({'message': '删除成功'}), 200
        else:
            logging.info(f'未找到对应对话，用户 ID: {user_id}，对话 ID: {conversation_id}')
            return jsonify({'message': '记录不存在或无权限删除'}), 404
    except Exception as e:
        logging.error(f'删除历史记录失败: {str(e)}，用户 ID: {user_id}，对话 ID: {conversation_id}')
        return jsonify({'message': f'删除历史记录失败: {str(e)}'}), 500

# 保存新对话
@app.route('/api/history', methods=['POST'])
def save_conversation():
    if 'user_id' not in session:
        return jsonify({'message': '请先登录'}), 401
    data = request.get_json()
    history_collection.insert_one(data)
    return jsonify({'message': '对话保存成功'}), 201

# 更新对话
@app.route('/api/history', methods=['PUT'])
def update_conversation():
    if 'user_id' not in session:
        return jsonify({'message': '请先登录'}), 401
    data = request.get_json()
    history_collection.replace_one({'id': data['id']}, data)
    return jsonify({'message': '对话更新成功'})

# 删除对话
@app.route('/api/history/<int:conversation_id>', methods=['DELETE'])
def delete_conversation(conversation_id):
    if 'user_id' not in session:
        return jsonify({'message': '请先登录'}), 401
    result = history_collection.delete_one({'id': conversation_id})
    if result.deleted_count > 0:
        return jsonify({'message': '对话删除成功'})
    else:
        return jsonify({'message': '未找到对应对话'}), 404

# 定义需要触发网页搜索的过时关键词
outdated_keywords = ["最新", "最近", "现在", "当前","今天"]

@app.route('/api/chat', methods=['POST'])
def chat():
    if 'user_id' not in session:
        return jsonify({'message': '请先登录'}), 401
    print("[DEBUG] 收到请求，表单数据:", request.form)
    print("[DEBUG] 上传文件:", request.files)
    # 处理文件上传
    file = request.files.get('file')
    text = request.form.get('query')
    history_json = request.form.get('history')
    history = json.loads(history_json) if history_json else []

    if file:
        file_path = f"uploads/{file.filename}"
        file.save(file_path)
        text += extract_text(file_path)

    # 调用AI模型，传递历史对话
    ai_response = query_ai(text, history)

    # 判断是否包含过时关键词，若包含则进行网页搜索
    should_search = any(keyword in text for keyword in outdated_keywords)

    if should_search:
        search_result = web_search(text)
        context = f"搜索结果: {search_result}\n"
        # 让 AI 基于搜索结果给出总结
        ai_response = query_ai("请根据以下搜索结果给出总结性报告：" + context, history + [{"role": "assistant", "content": context}])
        if not isinstance(ai_response, dict):
            ai_response = {
                "text": f"错误：AI响应非字典类型，原始响应: {ai_response}",
                "confidence": 0.0
            }

    print("[DEBUG] 最终响应:", ai_response)
    return jsonify({"response": ai_response['text']})
#知识库内容: {db_result}


# client_vector = MongoClient('mongodb://localhost:27017/')
# db_vector = client_vector['knowledge_db']
# model = SentenceTransformer('paraphrase-multilingual-MiniLM-L12-v2')

# def search_vector_db(query):
#     query_vec = model.encode(query).tolist()
    
#     results = db_vector.vectors.aggregate([
#         {"$vectorSearch": {
#             "queryVector": query_vec,
#             "path": "vector",
#             "numCandidates": 100,
#             "limit": 3,
#             "index": "vector_index"
#         }}
#     ])
    
#     return [doc['text'] for doc in results]


# API 网关接口
@app.route('/api/gateway', methods=['POST'])
def api_gateway():
    data = request.get_json()
    question = data.get('question')
    if not question:
        return jsonify({'message': '问题不能为空'}), 400
    
    # 转发至时间处理服务
    return time_processing_service(question)



def time_processing_service(question):
    # 判断是否需要实时工具
    if "现在几点了？" in question:
        time_data = get_current_time()
        standardized_time = standardize_time_data(time_data)
        final_answer = integrate_time_to_answer(question, standardized_time)
        return jsonify({'answer': final_answer})
    else:
        # 若不是时间相关问题，可调用原有的 AI 回答逻辑
        ai_response = query_ai(question)
        return jsonify({'answer': ai_response['text']})

def get_current_time():
    try:
        # 先尝试调用第三方时间 API
        response = requests.get('https://worldtimeapi.org/api/ip')
        if response.status_code == 200:
            return response.json()
    except Exception as e:
        logging.error(f'调用第三方时间 API 失败: {str(e)}')
    
    # 若第三方 API 失败，获取服务器本地时间
    local_time = datetime.datetime.now()
    return {
        'datetime': local_time.strftime('%Y-%m-%dT%H:%M:%S.%f%z'),
        'timezone': str(local_time.tzinfo)
    }

def standardize_time_data(time_data):
    dt = datetime.datetime.fromisoformat(time_data['datetime'])
    return dt.strftime('%Y 年 %m 月 %d 日 %H 时 %M 分 %S 秒')

def integrate_time_to_answer(question, time_data):
    return f"{question} 现在是 {time_data}"


def web_search(query):
    search_url = f"https://www.baidu.com/s?wd={query}"
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'}
    
    try:
        response = requests.get(search_url, headers=headers)
        response.encoding = response.apparent_encoding  # 确保正确处理编码
        soup = BeautifulSoup(response.text, 'html.parser')
        
        # 提取搜索结果
        results = []
        # 尝试新的选择器
        for item in soup.select('div#content_left > div.result.c-container.xpath-log'):
            title = item.select_one('h3.t a').text.strip() if item.select_one('h3.t a') else "无标题"
            abstract = item.select_one('div.c-abstract').text.strip() if item.select_one('div.c-abstract') else "无摘要"
            results.append(f"{title}: {abstract}")
            
        if not results:
            # 如果上面的选择器没找到结果，尝试另一种可能的结构
            for item in soup.select('div#content_left > div.result.c-container'):
                title = item.select_one('h3.t a').text.strip() if item.select_one('h3.t a') else "无标题"
                abstract = item.select_one('div.c-abstract').text.strip() if item.select_one('div.c-abstract') else "无摘要"
                results.append(f"{title}: {abstract}")

        return '\n'.join(results[:10])
    except Exception as e:
        return f"搜索失败: {str(e)}"






if __name__ == '__main__':
    if not os.path.exists('uploads'):
        os.makedirs('uploads')
    app.run(debug=True, threaded=False, processes=1)  # 禁用多线程和多进程